from typing import List, Optional, Dict, Any
from datetime import datetime, timedelta
from bson import ObjectId
from app.models.user import UserCreate, UserUpdate, UserStatus, UserRole
from app.core.security import get_password_hash
from app.services.role_service import RoleService
import logging

logger = logging.getLogger(__name__)


class UserService:
    @staticmethod
    async def get_user_stats(db):
        """获取用户统计信息"""
        try:
            total_users = await db.users.count_documents({"status": {"$ne": UserStatus.DELETED}})
            active_users = await db.users.count_documents({"status": UserStatus.ACTIVE})
            inactive_users = await db.users.count_documents({"status": UserStatus.INACTIVE})
            
            # 计算本月新增用户
            now = datetime.now()
            month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            new_users_this_month = await db.users.count_documents({
                "created_at": {"$gte": month_start},
                "status": {"$ne": UserStatus.DELETED}
            })
            
            # 计算上月新增用户
            last_month = now.month - 1 if now.month > 1 else 12
            last_month_year = now.year if now.month > 1 else now.year - 1
            last_month_start = datetime(last_month_year, last_month, 1)
            last_month_end = month_start - timedelta(seconds=1)
            last_month_users = await db.users.count_documents({
                "created_at": {"$gte": last_month_start, "$lte": last_month_end},
                "status": {"$ne": UserStatus.DELETED}
            })
            
            # 计算增长率
            user_growth_rate = 0
            if last_month_users > 0:
                user_growth_rate = round((new_users_this_month - last_month_users) / last_month_users * 100, 2)
            elif new_users_this_month > 0:
                user_growth_rate = 100
            
            stats_data = {
                "total_users": total_users,
                "active_users": active_users,
                "inactive_users": inactive_users,
                "new_users_this_month": new_users_this_month,
                "user_growth_rate": user_growth_rate
            }
            
            return stats_data
        except Exception as e:
            logger.error(f"Error retrieving user stats: {str(e)}")
            raise
    
    @staticmethod
    async def get_departments(db):
        """获取所有部门"""
        return await db.users.distinct("department_id", {"department_id": {"$ne": None}})
    
    @staticmethod
    def get_roles():
        """获取所有角色"""
        return [role.value for role in UserRole]
    
    @staticmethod
    async def search_users_for_project(db, search: str, project, limit: int = 50):
        """搜索项目成员"""
        # 获取项目已有的成员ID
        existing_member_ids = [member['user_id'] for member in project.get('members', [])]
        
        # 构建搜索条件
        query = {
            "status": UserStatus.ACTIVE,  # 只搜索活跃用户
            "$or": [
                {"username": {"$regex": search, "$options": "i"}},
                {"name": {"$regex": search, "$options": "i"}},
                {"email": {"$regex": search, "$options": "i"}},
                {"phone": {"$regex": search, "$options": "i"}}
            ]
        }
        
        # 排除已在项目中的成员
        if existing_member_ids:
            query["_id"] = {"$nin": [ObjectId(id) for id in existing_member_ids]}
        
        # 执行查询
        cursor = db.users.find(query, {"username": 1, "name": 1, "email": 1, "avatar": 1}).limit(limit)
        users = await cursor.to_list(length=limit)
        
        # 格式化返回数据
        return [
            {
                "id": str(user["_id"]),
                "name": user.get("name"),
                "email": user.get("email"),
                "avatar": user.get("avatar")
            }
            for user in users
        ]
    
    @staticmethod
    async def search_users_for_project_by_id(db, search: str, project_id: str, limit: int = 50):
        """通过项目ID搜索可添加到项目的用户"""
        try:
            # 查找项目信息
            project = await db.projects.find_one(
                {"_id": ObjectId(project_id)},
                {"members.user_id": 1}
            )
            
            # 如果项目不存在，返回空结果
            if not project:
                return []
            
            # 调用现有方法进行搜索
            return await UserService.search_users_for_project(db, search, project, limit)
        except Exception as e:
            logger.error(f"Error searching users for project: {str(e)}")
            raise
    
    @staticmethod
    async def get_users(db, search: Optional[str] = None, 
                        status: Optional[UserStatus] = None,
                        role: Optional[str] = None,
                        department: Optional[str] = None,
                        skip: int = 0, limit: int = 10,
                        sort_by: str = "created_at",
                        sort_order: int = -1):
        """获取用户列表"""
        # 构建查询条件
        query = {"status": {"$ne": UserStatus.DELETED}}  # 过滤掉已删除的用户
        
        # 应用搜索条件
        if search:
            query["$or"] = [
                {"username": {"$regex": search, "$options": "i"}},
                {"name": {"$regex": search, "$options": "i"}},
                {"email": {"$regex": search, "$options": "i"}},
                {"phone": {"$regex": search, "$options": "i"}}
            ]
        
        # 应用状态筛选
        if status is not None:
            query["status"] = status
        
        # 应用角色筛选
        if role:
            # 尝试通过代码查找角色
            role_doc = await db.roles.find_one({"code": role})
            if role_doc:
                query["system_roles"] = {"$in": [str(role_doc["_id"])]}
            elif ObjectId.is_valid(role):
                # 如果是ID，直接使用
                query["system_roles"] = {"$in": [role]}
            else:
                # 角色不存在，返回空
                return [], 0

        # 应用部门筛选
        if department:
            # 如果department是字符串，可能是单个部门ID或多个部门ID（逗号分隔）
            if isinstance(department, str):
                # 检查是否包含逗号（多个部门ID）
                if ',' in department:
                    # 多个部门ID，使用 $in 查询
                    dept_ids = [d.strip() for d in department.split(',') if d.strip()]
                    valid_dept_ids = []
                    for dept_id in dept_ids:
                        if ObjectId.is_valid(dept_id):
                            valid_dept_ids.append(ObjectId(dept_id))
                        else:
                            # 如果不是有效的ObjectId，可能是部门名称，需要查找部门ID
                            dept = await db.departments.find_one({"name": dept_id})
                            if dept:
                                valid_dept_ids.append(dept["_id"])
                    if valid_dept_ids:
                        query["department_id"] = {"$in": valid_dept_ids}
                    else:
                        # 没有有效的部门ID，返回空结果
                        return [], 0
                elif ObjectId.is_valid(department):
                    # 单个有效的ObjectId
                    query["department_id"] = ObjectId(department)
                else:
                    # 单个部门名称，需要查找部门ID
                    dept = await db.departments.find_one({"name": department})
                    if dept:
                        query["department_id"] = dept["_id"]
                    else:
                        # 部门不存在，返回空结果
                        return [], 0
            else:
                query["department_id"] = department
        
        # 计算总数
        total = await db.users.count_documents(query)
        
        # 构建排序条件
        sort_criteria = [(sort_by, sort_order)]
        
        # 执行分页查询
        cursor = db.users.find(query, {"hashed_password": 0}).sort(sort_criteria).skip(skip).limit(limit)
        users = await cursor.to_list(length=limit)
        
        # 获取所有角色代码映射
        all_roles = await db.roles.find({}, {"code": 1}).to_list(length=None)
        role_map = {str(r["_id"]): r["code"] for r in all_roles if "code" in r}
        
        # 收集所有部门ID，批量查询部门信息
        department_ids = set()
        for user in users:
            dept_id = user.get("department_id")
            if dept_id:
                department_ids.add(str(dept_id))
        
        # 批量查询部门信息
        department_map = {}
        if department_ids:
            try:
                dept_object_ids = [ObjectId(did) for did in department_ids if ObjectId.is_valid(did)]
                if dept_object_ids:
                    departments = await db.departments.find(
                        {"_id": {"$in": dept_object_ids}},
                        {"_id": 1, "name": 1}
                    ).to_list(length=None)
                    department_map = {str(d["_id"]): d.get("name", "") for d in departments}
            except Exception as e:
                logger.warning(f"Error fetching departments: {str(e)}")
        
        # 格式化用户响应数据
        items = []
        for user in users:
            # 转换角色为字符串
            user_roles = user.get("system_roles", [])
            user_roles_codes = [role_map.get(rid) for rid in user_roles if rid in role_map]
            
            # 获取部门信息
            dept_id = user.get("department_id")
            dept_name = None
            if dept_id:
                dept_id_str = str(dept_id)
                dept_name = department_map.get(dept_id_str)
            
            from app.models.user import UserResponse
            user_response = UserResponse(
                id=str(user["_id"]),
                username=user.get("username", user.get("name", "")),  # 如果没有username，使用name作为fallback
                name=user["name"],
                email=user["email"],
                department_id=str(dept_id) if dept_id else None,
                department=dept_name,  # 添加部门名称
                position=user.get("position"),
                phone=user.get("phone"),
                avatar=user.get("avatar"),
                status=user["status"],
                is_verified=user.get("is_verified", False),
                system_roles=user_roles,
                roles=user_roles_codes,
                permissions=user.get("permissions", []),
                created_at=user.get("created_at"),
                updated_at=user.get("updated_at"),
                last_login=user.get("last_login"),
                login_count=user.get("login_count", 0)
            )
            items.append(user_response.model_dump())
        
        return items, total
    
    @staticmethod
    async def get_user(db, user_id: str):
        """
        获取单个用户详情
        """
        # 验证ObjectId格式
        try:
            object_id = ObjectId(user_id)
        except Exception:
            logger.error(f"Invalid user ID format: {user_id}")
            return None
        
        # 查询用户
        user = await db.users.find_one({"_id": object_id}, {"hashed_password": 0})
        if not user:
            return None
        
        # 获取部门信息
        dept_id = user.get("department_id")
        dept_name = None
        if dept_id:
            try:
                dept = await db.departments.find_one({"_id": ObjectId(dept_id)}, {"name": 1})
                if dept:
                    dept_name = dept.get("name")
            except Exception as e:
                logger.warning(f"Error fetching department for user {user_id}: {str(e)}")
        
        # 转换为响应模型
        user_response = {
            "id": str(user["_id"]),
            **{k: v for k, v in user.items() if k != "_id"},
            "department_id": str(dept_id) if dept_id else None,
            "department": dept_name,
            "roles": await RoleService.get_role_codes_by_ids(db, user.get("system_roles", []))
        }
        
        return user_response
    
    @staticmethod
    async def create_user(db, user_in):
        """
        创建用户
        """
        from app.core.security import get_password_hash
        from app.core.permissions import get_permissions_for_role
        from datetime import datetime
        
        # 检查用户名是否已存在
        existing_username = await db.users.find_one({"username": user_in.username})
        if existing_username:
            logger.warning(f"Username already exists: {user_in.username}")
            raise ValueError("Username already exists")
        
        # 检查邮箱是否已存在
        existing_email = await db.users.find_one({"email": user_in.email})
        if existing_email:
            logger.warning(f"Email already registered: {user_in.email}")
            raise ValueError("Email already registered")
            
        # Resolve roles to system_roles if provided
        if hasattr(user_in, "roles") and user_in.roles:
            role_docs = await db.roles.find({"code": {"$in": user_in.roles}}).to_list(length=None)
            user_in.system_roles = [str(r["_id"]) for r in role_docs]
        
        # 处理部门字段：如果前端传递的是部门名称，需要转换为部门ID
        user_doc_data = user_in.model_dump(exclude={"password"})
        if "department" in user_doc_data and user_doc_data["department"]:
            department_name = user_doc_data.pop("department")
            # 根据部门名称查找部门ID
            department = await db.departments.find_one({"name": department_name})
            if department:
                user_doc_data["department_id"] = ObjectId(department["_id"])
            else:
                # 如果部门不存在，清空部门ID
                user_doc_data["department_id"] = None
        elif "department" in user_doc_data and not user_doc_data["department"]:
            # 如果部门为空，清空部门ID
            user_doc_data.pop("department")
            user_doc_data["department_id"] = None
        elif "department_id" in user_doc_data and user_doc_data["department_id"]:
            # 如果直接传递了部门ID，转换为ObjectId
            dept_id = user_doc_data["department_id"]
            if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
                user_doc_data["department_id"] = ObjectId(dept_id)
            elif not isinstance(dept_id, ObjectId):
                user_doc_data["department_id"] = None
        
        # 生成密码哈希
        hashed_password = get_password_hash(user_in.password)
        
        # 获取角色对应的权限
        permissions = []
        for role_id in user_in.system_roles:
            try:
                role = await RoleService.get_role_with_permissions(db, role_id)
                if role:
                    permissions.extend(p for p in role.get("permissions", []) if p not in permissions)
            except Exception:
                logger.warning(f"Role not found or error fetching permissions: {role_id}")
                continue
        
        # 创建用户文档（使用已处理过的 user_doc_data）
        user_doc = user_doc_data
        user_doc.update({
            "hashed_password": hashed_password,
            "permissions": permissions,
            "created_at": datetime.utcnow(),
            "updated_at": datetime.utcnow()
        })
        
        # 插入数据库
        result = await db.users.insert_one(user_doc)
        
        # 获取创建的用户
        created_user = await db.users.find_one({"_id": result.inserted_id}, {"hashed_password": 0})
        
        if not created_user:
            logger.error(f"Failed to retrieve created user with ID: {result.inserted_id}")
            return None
        
        # 获取部门信息
        dept_id = created_user.get("department_id")
        dept_name = None
        if dept_id:
            try:
                dept = await db.departments.find_one({"_id": ObjectId(dept_id)}, {"name": 1})
                if dept:
                    dept_name = dept.get("name")
            except Exception as e:
                logger.warning(f"Error fetching department for created user: {str(e)}")
        
        # 转换为响应模型，确保所有 ObjectId 都转换为字符串
        user_response = {
            "id": str(created_user["_id"]),
            **{k: str(v) if isinstance(v, ObjectId) else v for k, v in created_user.items() if k != "_id"},
            "department_id": str(dept_id) if dept_id else None,
            "department": dept_name,
            "roles": await RoleService.get_role_codes_by_ids(db, created_user.get("system_roles", []))
        }
        
        logger.info(f"User created successfully: {user_response['id']}")
        return user_response
    
    @staticmethod
    async def update_user(db, user_id: str, user_in, is_self: bool):
        """
        更新用户信息
        """
        from app.core.security import get_password_hash
        from app.core.permissions import get_permissions_for_role
        from datetime import datetime
        
        # 验证ObjectId格式
        try:
            object_id = ObjectId(user_id)
        except Exception:
            logger.error(f"Invalid user ID format: {user_id}")
            return None
        
        # 查询用户
        db_user = await db.users.find_one({"_id": object_id})
        if not db_user:
            logger.warning(f"User not found: {user_id}")
            return None
        
        # 如果是用户本人，限制只能更新部分字段
        update_data = user_in.model_dump(exclude_unset=True)
        
        # 处理部门字段：如果前端传递的是部门名称，需要转换为部门ID
        if "department" in update_data and update_data["department"]:
            department_name = update_data.pop("department")
            # 根据部门名称查找部门ID
            department = await db.departments.find_one({"name": department_name})
            if department:
                update_data["department_id"] = ObjectId(department["_id"])
            else:
                # 如果部门不存在，清空部门ID
                update_data["department_id"] = None
        elif "department" in update_data and not update_data["department"]:
            # 如果部门为空，清空部门ID
            update_data.pop("department")
            update_data["department_id"] = None
        elif "department_id" in update_data and update_data["department_id"]:
            # 如果直接传递了部门ID，转换为ObjectId
            dept_id = update_data["department_id"]
            if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
                update_data["department_id"] = ObjectId(dept_id)
            elif not isinstance(dept_id, ObjectId):
                update_data["department_id"] = None
        
        # Resolve roles to system_roles
        if "roles" in update_data:
            roles = update_data.pop("roles")
            if roles is not None:
                role_docs = await db.roles.find({"code": {"$in": roles}}).to_list(length=None)
                update_data["system_roles"] = [str(r["_id"]) for r in role_docs]
        
        if is_self:
            # 检查是否尝试更新不允许的字段
            restricted_fields = ["system_roles", "permissions", "status", "created_at"]
            for field in restricted_fields:
                if field in update_data:
                    del update_data[field]
        
        # 如果包含密码，则生成哈希
        if "password" in update_data:
            update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
        
        # 如果更新了角色，则更新权限
        if "system_roles" in update_data:
            permissions = []
            for role_id in update_data["system_roles"]:
                try:
                    role = await RoleService.get_role_with_permissions(db, role_id)
                    if role:
                        permissions.extend(p for p in role.get("permissions", []) if p not in permissions)
                except Exception:
                    continue
            update_data["permissions"] = permissions
        
        # 更新时间
        update_data["updated_at"] = datetime.utcnow()
        
        # 执行更新
        result = await db.users.update_one(
            {"_id": object_id},
            {"$set": update_data}
        )
        
        if result.modified_count == 0:
            logger.warning(f"Failed to update user: {user_id}")
            return None
        
        # 获取更新后的用户
        updated_user = await db.users.find_one({"_id": object_id}, {"hashed_password": 0})
        
        # 获取部门信息
        dept_id = updated_user.get("department_id")
        dept_name = None
        if dept_id:
            try:
                dept = await db.departments.find_one({"_id": ObjectId(dept_id)}, {"name": 1})
                if dept:
                    dept_name = dept.get("name")
            except Exception as e:
                logger.warning(f"Error fetching department for user {user_id}: {str(e)}")
        
        # 转换为响应模型，确保所有 ObjectId 都转换为字符串
        user_response = {
            "id": str(updated_user["_id"]),
            **{k: str(v) if isinstance(v, ObjectId) else v for k, v in updated_user.items() if k != "_id"},
            "department_id": str(dept_id) if dept_id else None,
            "department": dept_name,
            "roles": await RoleService.get_role_codes_by_ids(db, updated_user.get("system_roles", []))
        }
        
        logger.info(f"User updated successfully: {user_id}")
        return user_response
    
    @staticmethod
    async def get_users_count(db, search: Optional[str] = None,
                             status: Optional[UserStatus] = None,
                             role: Optional[str] = None,
                             department: Optional[str] = None):
        """
        获取用户数量
        """
        # 构建查询条件
        query = {"status": {"$ne": UserStatus.DELETED}}  # 过滤掉已删除的用户
        
        # 应用搜索条件
        if search:
            query["$or"] = [
                {"username": {"$regex": search, "$options": "i"}},
                {"name": {"$regex": search, "$options": "i"}},
                {"email": {"$regex": search, "$options": "i"}},
                {"phone": {"$regex": search, "$options": "i"}}
            ]
        
        # 应用状态筛选
        if status is not None:
            query["status"] = status
        
        # 应用角色筛选
        if role:
            # 尝试通过代码查找角色
            role_doc = await db.roles.find_one({"code": role})
            if role_doc:
                query["system_roles"] = {"$in": [str(role_doc["_id"])]}
            elif ObjectId.is_valid(role):
                # 如果是ID，直接使用
                query["system_roles"] = {"$in": [role]}
            else:
                # 角色不存在，返回0
                return 0

        # 应用部门筛选
        if department:
            # 如果department是字符串，可能是单个部门ID或多个部门ID（逗号分隔）
            if isinstance(department, str):
                # 检查是否包含逗号（多个部门ID）
                if ',' in department:
                    # 多个部门ID，使用 $in 查询
                    dept_ids = [d.strip() for d in department.split(',') if d.strip()]
                    valid_dept_ids = []
                    for dept_id in dept_ids:
                        if ObjectId.is_valid(dept_id):
                            valid_dept_ids.append(ObjectId(dept_id))
                        else:
                            # 如果不是有效的ObjectId，可能是部门名称，需要查找部门ID
                            dept = await db.departments.find_one({"name": dept_id})
                            if dept:
                                valid_dept_ids.append(dept["_id"])
                    if valid_dept_ids:
                        query["department_id"] = {"$in": valid_dept_ids}
                    else:
                        # 没有有效的部门ID，返回0
                        return 0
                elif ObjectId.is_valid(department):
                    # 单个有效的ObjectId
                    query["department_id"] = ObjectId(department)
                else:
                    # 单个部门名称，需要查找部门ID
                    dept = await db.departments.find_one({"name": department})
                    if dept:
                        query["department_id"] = dept["_id"]
                    else:
                        # 部门不存在，返回0
                        return 0
            else:
                query["department_id"] = department
        
        # 计算总数
        total = await db.users.count_documents(query)
        
        return total
